package com.csaba.connector.bha.model;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Random;
import java.util.logging.Logger;

import com.csaba.connector.ServiceException;
import com.csaba.connector.bha.Codes;
import com.csaba.connector.bha.SimpleNodeHelper;
import com.csaba.connector.bha.com.SecureCommunication;
import com.csaba.connector.model.Session;
import com.csaba.util.LoggerHelper;
import com.ind.simplenode.SimpleNode;

public class BHASession extends Session
{
	private final static Logger logger = LoggerHelper.getDefaultLogger();
	private SecureCommunication com;
	private HashMap<String, Boolean> functions;

	public BHASession() throws ServiceException
	{
		super();
		setBank(BHABank.getInstance());

		final byte[] random = new byte[200];
		final Random randomGen = new Random(); //XXX this is not a secure a random.
		randomGen.nextBytes(random);

		try
		{
			com = new SecureCommunication(random, new URL(Codes.SERVER_URL));
		}
		catch ( final MalformedURLException ex )
		{
			throw new ServiceException("Invalid server URL: " + Codes.SERVER_URL, ex);
		}

	}

	@Override
	public void invalidateSession() throws ServiceException
	{
		super.invalidateSession();
		com.clearSession();
		com = null;
	}

	public synchronized SimpleNode sendRequest( final String requesterId, final String requestName,
			final SimpleNode requestData ) throws ServiceException
	{
		if ( !activeSession )
		{
			throw new ServiceException("Session is already invalidated. Cannot be used anymore. SessionID = "
					+ getSessionId());
		}

		logger.info("Invoking request: " + requestName);
		if ( com == null )
		{
			throw new ServiceException("SessionService is not initialized or authenticated yet.");
		}
		final SimpleNode request = new SimpleNode();
		request.set("requestName", requestName);
		request.set("request", requestData);
		try
		{
			request.set("clientIp", InetAddress.getLocalHost().getHostAddress());
		}
		catch ( final UnknownHostException ex1 )
		{
			throw new ServiceException("Cannot get local IP " + requestName, ex1);
		}
		request.set("languageId", "hu");
		request.set("countryCode", "hu");
		if ( requesterId != null && Codes.FUNCTION_CODES.containsKey(requesterId) )
		{
			request.set("functionId", Codes.FUNCTION_CODES.get(requesterId));
			request.set("requesterId", requesterId);
		}

		SimpleNode response = null;
		try
		{
			SimpleNodeHelper.dumpNode("request data for " + requestName, request);
			response = com.sendRequest(request);
			SimpleNodeHelper.dumpNode("response data for " + requestName, response);
		}
		catch ( final Exception ex )
		{
			throw new ServiceException("Error during processing the request " + requestName, ex);
		}

		if ( getSessionId() == null )
			setSessionId(com.getSessionId());

		final int rc = response.getInt("rc");
		final String rcText = response.getString("rcText");
		final String rcServiceErrorCode = response.getString("rcServiceErrorCode");
		final String timestamp = response.getString("timestamp");

		logger.info("serverTime=" + timestamp + " rc=" + rc + " rcText=\"" + rcText + "\" rcServiceErrorCode="
				+ rcServiceErrorCode);

		if ( response.exists("adminMessage") )
		{
			final String adminMessage = response.getString("adminMessage");
			logger.warning("Admin Message: " + adminMessage); //XXX admin message should be displayed in a dialog or something.
		}

		if ( rc != 0 )
		{
			throw new ServiceException("Bank error. ", rcText + " (" + rc + ")");
		}

		final SimpleNode responseData = response.getNode("response");

		return responseData;
	}

	public boolean isFunctionEnabled( final String functionId )
	{
		return functions.containsKey(functionId);
	}

	public boolean isAuthRequired( final String functionId )
	{
		if ( functions.containsKey(functionId) )
			return functions.get(functionId);
		logger.warning("isAuthRequired: Function is not enabled: " + functionId);
		return false;
	}

	public void setFunctions( final SimpleNode[] functions )
	{
		this.functions = new HashMap<String, Boolean>();

		logger.fine("Following functions are enabled:");
		for ( final SimpleNode node : functions )
		{
			final String functionId = node.getString("functionId");
			final boolean authRequired = node.getBoolean("needAuthorization");
			logger.fine(" - " + functionId + " (authentication " + ( authRequired ? "is" : "isn't" ) + " required)");
			this.functions.put(functionId, authRequired);
		}
	}

}
